﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Ninject.Core.Parameters;
using Milkify.Controllers;

namespace Milkify
{
    public class MilkifyControllerFactory : IControllerFactory
    {
        private const string ControllerTypeSuffix = "Controller";

        private object mControllerTypesLock = new object();
        private Dictionary<string, Type> mControllerTypes;

        #region IControllerFactory Members

        public IController Create(ControllerContext context, string controllerName)
        {
            Type controllerType = GetControllerType(controllerName);
            IController controller = (IController)KernelContainer.Kernel.Get(controllerType, With.Parameters.ConstructorArgument("context", context));
            return controller;
        }

        #endregion

        private Type GetControllerType(string controllerName)
        {
            if (mControllerTypes == null)
            {
                lock (mControllerTypesLock)
                {
                    if (mControllerTypes == null)
                    {
                        Dictionary<string, Type> controllerTypes = new Dictionary<string, Type>();
                        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                        {
                            foreach (Type type in assembly.GetTypes())
                            {
                                if (IsController(type))
                                {
                                    string name = GetControllerName(type);
                                    controllerTypes.Add(name, type);
                                }
                            }
                        }

                        mControllerTypes = controllerTypes;
                    }
                }
            }

            return mControllerTypes[controllerName];
        }

        private string GetControllerName(Type type)
        {
            return type.Name.Substring(0, type.Name.Length - ControllerTypeSuffix.Length);
        }

        internal static bool IsController(Type type)
        {
            if (type.IsInterface || type == typeof(Controller))
                return false;
            return type.Name.EndsWith(ControllerTypeSuffix) && typeof(IController).IsAssignableFrom(type);
        }
    }
}
